package cn.pink.core.entity;

import cn.pink.core.support.EntityUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @Author: pink
 * @Date: 2022/7/21 17:21
 */
public class EntityProxy implements MethodInterceptor{
    private Class<?> entityClass;
    private AbstractEntity proxyEntity;

    /** 保存更新属性 */
    private Set<String> updates = new HashSet<>();

    public EntityProxy(Class<?> clazz) {
        this.entityClass = clazz;
    }

    public void createProxy(Object... key) {
        Enhancer enhancer = new Enhancer();
        // 设置代理目标
        enhancer.setSuperclass(this.entityClass);
        // 设置回调
        enhancer.setCallback(this);
        enhancer.setClassLoader(this.entityClass.getClassLoader());

        if (key.length == 0) {
            proxyEntity = (AbstractEntity) enhancer.create();
        }
        else if (key.length == 1) {
            //Entity 如果初始化1个参数 必须为humanId
            proxyEntity = (AbstractEntity) enhancer.create(new Class[]{String.class}, key);
        }
        else if (key.length == 2) {
            proxyEntity = (AbstractEntity) enhancer.create(new Class[]{String.class, EntityUtils.getKeyType(this.getEntityClass())}, key);
        }
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        Object result = proxy.invokeSuper(obj, args);

        if (method.getName().toUpperCase().startsWith("SET")) {
            updates.add(proxyEntity.getKeyPrefix() + "." + EntityUtils.getAttrByMethod(method.getName()));
        }

        return result;
    }

    /**
     * 获取字段变化
     */
    public Map<String, String> getUpdate() {
        Map<String, String> map = new HashMap<>();

        try {
            for (String key : updates) {
                Field field = entityClass.getDeclaredField(EntityUtils.getFiledByKey(key));

                if(Modifier.isTransient(field.getModifiers())) {
                    continue;
                }

                Object value = entityClass.getMethod(EntityUtils.getGetterName(field)).invoke(this.proxyEntity);
                map.put(key, EntityUtils.generateTypeString(field.getType(), value));
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        return map;
    }

    /**
     * 初始化entity数据
     */
    public void initEntity(Map<String, Object> data) {
        if (data.isEmpty()) {
            return;
        }

        EntityUtils.initEntity(this.getEntityClass(), proxyEntity, data);

        this.reset();
    }

    /**
     * 重置proxy状态信息
     */
    public void reset() {
        this.updates.clear();
    }

    public AbstractEntity getEntity() {
        return this.proxyEntity;
    }

    public Class<?> getEntityClass(){
        return this.entityClass;
    }
}
